/*
  喜马拉雅签名Demo

  作者：Decade Chan
  日期：2020-12-25

  本例使用到的测试数据

  "app_key": "99b37417e1185eda1378600593b45c40"
  "device_id":"2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d",
  "nonce":"kj9OLysvg6",
  "timestamp":"1568278327523",
  "grant_type":"js_client_credentials"
  "app_secret": dd7a46b12fe8a304ef17892c89ede22a

  最终输出结果
  0072d8523cd07537ec4a00b4c3c84997
  { "code": 0, "message": "success", "signature": "0072d8523cd07537ec4a00b4c3c84997" }

  按字典首字母排序好后的参数字符串
  client_id=99b37417e1185eda1378600593b45c40&device_id=2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d&grant_type=js_client_credentials&nonce=kj9OLysvg6&timestamp=1568278327523
*/

const express = require('express');
// 方法1
const CryptoJS = require('crypto-js');
// 方法2
const crypto = require('crypto');

const app = express();

// 本例测试用模拟入参, 喜马拉雅会返回
const param = {
  "client_id":"99b37417e1185eda1378600593b45c40",
  "device_id":"2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d",
  "nonce":"kj9OLysvg6",
  "timestamp":"1568278327523",
  "params": '{"client_id":"99b37417e1185eda1378600593b45c40","device_id":"2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d","nonce":"kj9OLysvg6","timestamp":"1568278327523","grant_type":"js_client_credentials"}'
}

const app_secret = 'dd7a46b12fe8a304ef17892c89ede22a';

function parseInputParams(param) {
  // 将入参参数转为参数字符串
  // 喜马拉雅返回的是字符串，所以我们先转为JSON
  let inputParam = JSON.parse(param.params);
  // 将key按照字典顺序进行排序
  let paramArray = [];
  let tmpKeys = Object.keys(inputParam).sort();
  for (let k=0; k<tmpKeys.length; k++) {
    let tmpStr = tmpKeys[k] + '=' + inputParam[tmpKeys[k]];
    paramArray.push(tmpStr)
  }
  return paramArray.join('&');
  // 期望结果
  // client_id=99b37417e1185eda1378600593b45c40&device_id=2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d&grant_type=js_client_credentials&nonce=kj9OLysvg6&timestamp=1568278327523
}

// 方法1：使用crypto-js （推荐） github 10.4k star
app.get('/sign', (req, res) => {
  // 处理入参
  let paramString = parseInputParams(param);
  // 将参数字符串转UTF-8
  paramString =  CryptoJS.enc.Utf8.parse(paramString);
  // 进行Base64编码
  const tmpBase64 = CryptoJS.enc.Base64.stringify(paramString);
  // 进行HmacSha1编码，使用app_secret作为key
  const tmpSha1 = CryptoJS.HmacSHA1(tmpBase64, app_secret);
  // 最后进行md5编码
  const tmpMd5 = CryptoJS.MD5(tmpSha1).toString();
  const result = tmpMd5;
  // 输出格式按照如下格式要求进行
  res.send(
    {
      code:0,
      message:'success',
      signature: result,
    }
  )

})

// 方法2：使用crypto
app.get('/sign2', (req, res) => {
  // 处理入参
  let paramString = parseInputParams(param);
  // 进行Base64编码
  const tmpBase64 = Buffer(paramString).toString('base64');
  // 进行HmacSha1编码，使用app_secret作为key
  const tmpSha1 = crypto.createHmac('sha1', app_secret).update(tmpBase64).digest();
  // 最后进行md5编码
  const tmpMd5 = crypto.createHash('md5').update(tmpSha1).digest('hex');
  const result = tmpMd5;
  // 输出格式按照如下格式要求进行
  res.send(
    {
      code:0,
      message:'success',
      signature: result,
    }
  )

})

app.listen(3001, () => {
  console.log('Example XiMaLaYa Sign app listening on port 3001');
})
